#ifndef __MPXT804__
#define __MPXT804__

#include <stdint.h>
#include <wm_regs.h>
#include <wm_uart.h>

#define MICROPY_HW_FREQ             CPU_CLK_240M       /* HAL定义CPU_CLK_[2M,40M,80M,160M,240M]等频率 */

#define ARR_LEN(arr) sizeof(arr) / sizeof(arr[0])  /* 获取数组长度, arr必须是数组名, 不能是指针变量 */
#define _P(group, port)  ((group)<<5 | port)       /* 按字节编码, 高3位存储port编号, A-0, B-1类推, 低5位存储引脚编号, PB12 = (1<<5) | 0x0C */

// 根据结构体成员指针, 计算出整个结构体的指针
#define container_of(ptr, type, member)  ((type*)((uintptr_t )(ptr) - (uintptr_t )&(((type*)0)->member)))

// GPIOA
#define PA0             _P(0, 0)
#define PA1             _P(0, 1)
#define PA2             _P(0, 2)
#define PA3             _P(0, 3)
#define PA4             _P(0, 4)
#define PA5             _P(0, 5)
#define PA6             _P(0, 6)
#define PA7             _P(0, 7)
#define PA8             _P(0, 8)
#define PA9             _P(0, 9)
#define PA10            _P(0, 10)
#define PA11            _P(0, 11)
#define PA12            _P(0, 12)
#define PA13            _P(0, 13)
#define PA14            _P(0, 14)
#define PA15            _P(0, 15)
#define PA16            _P(0, 16)
#define PA17            _P(0, 17)
#define PA18            _P(0, 18)
#define PA19            _P(0, 19)
#define PA20            _P(0, 20)
#define PA21            _P(0, 21)
#define PA22            _P(0, 22)
#define PA23            _P(0, 23)
#define PA24            _P(0, 24)
#define PA25            _P(0, 25)
#define PA26            _P(0, 26)
#define PA27            _P(0, 27)
#define PA28            _P(0, 28)
#define PA29            _P(0, 29)
#define PA30            _P(0, 30)
#define PA31            _P(0, 31)

// GPIOB
#define PB0             _P(1, 0)
#define PB1             _P(1, 1)
#define PB2             _P(1, 2)
#define PB3             _P(1, 3)
#define PB4             _P(1, 4)
#define PB5             _P(1, 5)
#define PB6             _P(1, 6)
#define PB7             _P(1, 7)
#define PB8             _P(1, 8)
#define PB9             _P(1, 9)
#define PB10            _P(1, 10)
#define PB11            _P(1, 11)
#define PB12            _P(1, 12)
#define PB13            _P(1, 13)
#define PB14            _P(1, 14)
#define PB15            _P(1, 15)
#define PB16            _P(1, 16)
#define PB17            _P(1, 17)
#define PB18            _P(1, 18)
#define PB19            _P(1, 19)
#define PB20            _P(1, 20)
#define PB21            _P(1, 21)
#define PB22            _P(1, 22)
#define PB23            _P(1, 23)
#define PB24            _P(1, 24)
#define PB25            _P(1, 25)
#define PB26            _P(1, 26)
#define PB27            _P(1, 27)
#define PB28            _P(1, 28)
#define PB29            _P(1, 29)
#define PB30            _P(1, 30)
#define PB31            _P(1, 31)

// pin=PB12, 通过下面2个宏获取对应的GPIOB, HAL_PIN_12
#define MICROPY_HW_PORT(pin)      ((GPIO_TypeDef *)(GPIOA_BASE + (pin >> 5) * 0x200))      /* 各组GPIO的基址差了0x0200, 可查看<wm_regs.h> */
#define MICROPY_HW_PIN(pin)       (1 << (pin & 0x1F))                                      /* 低5位存储引脚编号, 对应0-31, HAL_PIN_x=(1<<x) */

#define MICROPY_HW_PORT_IDX(pin)  ((uint8_t)(pin>>5))                                      /* 获取GPIO编号(A-0, B-1) */
#define MICROPY_HW_PIN_IDX(pin)   (pin&0x1F)                                               /* 获取引脚编号(从0开始) */

// 硬件资源情况, 用于定义资源描述结构(不用修改)
#define MICROPY_HW_MAX_UART_CNT    0x06
#define MICROPY_HW_MAX_I2C_CNT     0x01
#define MICROPY_HW_MAX_I2S_CNT     0x01
#define MICROPY_HW_MAX_SPI_CNT     0x01
#define MICROPY_HW_MAX_SDIO_CNT    0x01
#define MICROPY_HW_MAX_TIMER_CNT   0x06
#define MICROPY_HW_MAX_PWM_CNT     0x05


// 关闭GPIO的复用功能
#define GPIO_AF_DISABLE(pin)  CLEAR_BIT(MICROPY_HW_PORT(pin)->AF_SEL, MICROPY_HW_PIN(pin))
	
// 向某位写入1或0
#define WRITE_BIT(reg, bit, is_set) do{  \
    if(is_set){                          \
        (reg) |= (1 << (bit));           \
    }else{                               \
        (reg) &= ~(1 << (bit));          \
    }                                    \
}while(0)


// 启动数据、指令cache, 注意W801的WIFI和蓝牙是否会炸(DMA启动要清除CACHE无效目录)
#define MP_HW_CACHE_INIT() do{                                                                                                \
	CACHE->CER=0x00;                                                                                                          \
    csi_cache_set_range(0,0x08000000,0,CACHE_CRCR_2M,1);        /* 2K, 映射片内QFlash 2MB区域 */                              \
    csi_cache_set_range(1,0x20000000,0,CACHE_CRCR_256K,1);       /* 4K, SRAM=160KB + 128KB, 映射必须是2的n次方,拆分2次映射 */  \
    csi_cache_set_range(2,0x20040000,0,CACHE_CRCR_32K,1);      /* 8k, SRAM映射最后的32KB */                                  \
    csi_cache_set_range(3,0x30000000,0,CACHE_CRCR_8M,1);        /* 16k, 映射片外PSRAM */                                      \
	CACHE->CER=0x11;                                                                                                          \
    csi_cache_disable_profile();                                /* 关闭性能分析, 统计命中率等 */                              \
}while(0)
	
// cache相关操作, 请查阅"include/arch/xt804/csi_core/core_804.h"
// 整个dcache无效
#define MP_HW_DCACHE_INV()   do{csi_dcache_invalid();}while(0)
// 清理整个dcache, 有新数据会回写到内存
#define MP_HW_DCACHE_CLEAN()  do{csi_dcache_clean();}while(0)
// 清理并无效整个dcache
#define MP_HW_DECACHE_CLEAN_INV() do{csi_dcache_clean_invalid();}while(0)

// 无效dcache某个地址范围
#define MP_HW_DCACHE_RANGE_INV(addr, size) do{csi_dcache_invalid_range(addr, size);}while(0)
// 清除dcache某个地址范围
#define MP_HW_DCACHE_RANGE_CLEAR(addr, size)  do{csi_dcache_clean_range(addr, size);}while(0)
// 无效并清理某个dcache地址范围
#define MP_HW_DCACHE_RANGE_CLEAR_INV(addr, size)  do{csi_dcache_clean_invalid_range(addr, size);}while(0)


// 串口GPIO、IRQ配置	
#define UART_GPIO_INIT(nr, irq) do{                                                                                            \
     __HAL_RCC_UART##nr##_CLK_ENABLE();                                                                                        \
	 __HAL_AFIO_REMAP_UART##nr##_TX(MICROPY_HW_PORT(MICROPY_HW_UART##nr##_TX), MICROPY_HW_PIN(MICROPY_HW_UART##nr##_TX));      \
	 __HAL_AFIO_REMAP_UART##nr##_RX(MICROPY_HW_PORT(MICROPY_HW_UART##nr##_RX), MICROPY_HW_PIN(MICROPY_HW_UART##nr##_RX));      \
	 HAL_NVIC_SetPriority(irq, MICROPY_HW_UART##nr##_PRI);                                                                     \
     HAL_NVIC_EnableIRQ(irq);                                                                                                  \
}while(0)
	
// 关闭串口时钟、重置GPIO
#define UART_GPIO_RESET(nr) do{                                                                                     \
	__HAL_RCC_UART##nr##_CLK_DISABLE();                                                                             \
	UART##nr->INTM |= UART_RX_INT_FLAG;   /* 屏蔽中断 */                                                            \
    HAL_GPIO_DeInit(MICROPY_HW_PORT(MICROPY_HW_UART##nr##_TX), MICROPY_HW_PIN(MICROPY_HW_UART##nr##_TX));           \
    HAL_GPIO_DeInit(MICROPY_HW_PORT(MICROPY_HW_UART##nr##_RX), MICROPY_HW_PIN(MICROPY_HW_UART##nr##_RX));           \
	GPIO_AF_DISABLE(MICROPY_HW_UART##nr##_TX);                                                                      \
	GPIO_AF_DISABLE(MICROPY_HW_UART##nr##_RX);                                                                      \
}while(0)
	

// 配置串口(初始化或重置)
#define UART_GPIO_CFG_CHECK(huart, nr, irq, is_reset) do{     \
	if(huart->Instance == UART##nr){                          \
		if(!is_reset){                                        \
	        UART_GPIO_INIT(nr, irq);                          \
		}else{                                                \
			UART_GPIO_RESET(nr);                              \
		}                                                     \
	}	                                                      \
}while(0)
	

// 配置PWM GPIO(初始化或重置)
#define PWM_GPIO_CFG(hpwm, nr, stop, is_reset) do{                                                                 \
    if(!is_reset){                                                                                                 \
        __HAL_AFIO_REMAP_PWM##nr(MICROPY_HW_PORT(MICROPY_HW_PWM_CH##nr), MICROPY_HW_PIN(MICROPY_HW_PWM_CH##nr));   \
    }else{                                                                                                         \
        if(stop){                                                                                                  \
            HAL_PWM_Stop(hpwm, nr);                                                                                \
        }                                                                                                          \
        HAL_GPIO_DeInit(MICROPY_HW_PORT(MICROPY_HW_PWM_CH##nr), MICROPY_HW_PIN(MICROPY_HW_PWM_CH##nr));            \
		GPIO_AF_DISABLE(MICROPY_HW_PWM_CH##nr);                                                                    \
    }                                                                                                              \
}while(0)


// DMA_IRQn(DMA_Channel0) => DMA_Channel0_IRQn
#define DMA_IRQn(dma)       (DMA_Channel3##_IRQn)

// DMA结构体配置
#define DMA_TAG_FILL(hdma, inst, dir, destinc, srcinc, align, mode, reqsrc) do{    \
    (hdma)->Instance = inst;                                                       \
    (hdma)->Init.Direction = dir;                                                  \
    (hdma)->Init.DestInc = destinc;                                                \
    (hdma)->Init.SrcInc = srcinc;                                                  \
    (hdma)->Init.DataAlignment = align;                                            \
    (hdma)->Init.Mode = mode;                                                      \
    (hdma)->Init.RequestSourceSel = reqsrc;                                        \
}while(0)


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 




#endif
